package org.hepeng.workx.spring.cloud.netflix.eureka.client;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.DiscoveryManager;
import com.netflix.discovery.EurekaClient;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hepeng.workx.spring.context.ApplicationContextHolder;
import org.joor.Reflect;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig;
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Objects;

/**
 * @author he peng
 */
public class EurekaDiscoveryClientUtils {

    public static DiscoveryClient getDiscoveryClient() {
        return ApplicationContextHolder.getApplicationContext().getBean(DiscoveryClient.class);
    }

    public static String getServiceInstanceId() {
        CloudEurekaInstanceConfig cloudEurekaInstanceConfig =
                ApplicationContextHolder.getApplicationContext()
                        .getBean(CloudEurekaInstanceConfig.class);
        return cloudEurekaInstanceConfig.getInstanceId();
    }

    public static EurekaDiscoveryClient.EurekaServiceInstance getServiceInstance() {
        ApplicationContext applicationContext = ApplicationContextHolder.getApplicationContext();
        Environment environment = applicationContext.getEnvironment();
        String applicationName = environment.getProperty("spring.application.name");
        String instanceId = getServiceInstanceId();
        List<ServiceInstance> instances = getDiscoveryClient().getInstances(applicationName);
        EurekaDiscoveryClient.EurekaServiceInstance serviceInstance = null;
        if (CollectionUtils.isNotEmpty(instances)) {
            for (ServiceInstance instance : instances) {
                if (! EurekaDiscoveryClient.EurekaServiceInstance.class.isAssignableFrom(instance.getClass())) {
                    continue;
                }
                EurekaDiscoveryClient.EurekaServiceInstance eurekaServiceInstance = (EurekaDiscoveryClient.EurekaServiceInstance) instance;
                if (StringUtils.equals(eurekaServiceInstance.getInstanceInfo().getInstanceId() , instanceId)) {
                    serviceInstance = eurekaServiceInstance;
                    break;
                }
            }
        }
        return serviceInstance;
    }

    public static InstanceInfo getServiceInstanceInfo() {
        InstanceInfo instanceInfo = getServiceInstanceInfoBySpring();
        if (Objects.isNull(instanceInfo)) {
            instanceInfo = getServiceInstanceInfoByNetflix();
        }
        return instanceInfo;
    }

    public static InstanceInfo getServiceInstanceInfoBySpring() {
        InstanceInfo instanceInfo = null;
        EurekaDiscoveryClient.EurekaServiceInstance serviceInstance = getServiceInstance();
        if (Objects.nonNull(serviceInstance)) {
            instanceInfo = serviceInstance.getInstanceInfo();
        }
        return instanceInfo;
    }

    public static InstanceInfo getServiceInstanceInfoByNetflix() {
        EurekaClient eurekaClient = DiscoveryManager.getInstance().getEurekaClient();
        return Reflect.on(eurekaClient).get("instanceInfo");
    }

    public static void status(InstanceInfo.InstanceStatus instanceStatus) {
        Assert.notNull(instanceStatus , "instanceStatus must not be null");
        InstanceInfo serviceInstanceInfo = getServiceInstanceInfoByNetflix();
        if (Objects.nonNull(serviceInstanceInfo)) {
            serviceInstanceInfo.setStatus(instanceStatus);
        }
    }
}
